
package com.common.service.base;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.PathParam;

import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.common.dao.base.BaseDAO;
import com.common.exception.LogicException;
import com.common.util.ConstantDefine;
import com.common.util.ReflectUtil;
import com.github.pagehelper.PageInfo;

import tk.mybatis.mapper.common.Mapper;

/**
 * 针对单表条件查询、增加、删除、修改
 */
public abstract class BaseService<T> implements IService<T> {
	protected Logger logger = null;
	
    public BaseService() {
    	logger = Logger.getLogger(getClass().getName());
	}
	@Autowired
	protected BaseDAO<T> baseDAO;
	@Autowired
    protected Mapper<T> mapper;
   
    
    public Mapper<T> getMapper() {
        return mapper;
    }
    
    @Override
    public T selectByKey(@PathParam("key") String key) {
        return mapper.selectByPrimaryKey(key);
    }
    
    @Override
	public T selectOne(T entity){
		return mapper.selectOne(entity);    	
    }
    
    @Override
    public List<T> select(T entity){
		return mapper.select(entity);    	
    }

    public boolean save(T entity) {
    	int rs = mapper.insert(entity);
    	return rs > 0;
    }

    public int deleteByPrimaryKey(String key) {
        return mapper.deleteByPrimaryKey(key);
    }
    
    public Map<String,Object> deleteByPrimaryKey(String[] key) {
        mapper.deleteByPrimaryKey(key);
        
		Map<String,Object> errorMap = new HashMap<>();
        errorMap.put(ConstantDefine.SUCCESS_MSG, ConstantDefine.SUCCESS_INFO);
        return errorMap;
    }
    
    /**
     * 根据主键更新实体全部字段，null值会被更新，小心使用
     */
    public int updateByPrimaryKey(T entity) {
        return mapper.updateByPrimaryKey(entity);
    }

    /**
     * 根据主键更新属性不为null的值
     */
    @Override
	public int updateNotNull(T entity) {
        return mapper.updateByPrimaryKeySelective(entity);
    }
    
    /**
	 * 校验通过，则新增数据
	 * @param entity 实体
	 * @return 返回 null，则保存成功，否则为错误信息
	 */
	@Override
    public Map<String,Object> checkAndSave(T entity){
		//先调用数据校验
		Map<String,Object> errorMap = this.check(entity);
		//存在错误则返回
		if(errorMap!=null && !errorMap.isEmpty()){
			return errorMap;
		}
		//保存
		boolean flag = save(entity);
		//必须new一个，否则会报空指针异常
		errorMap = new HashMap<>();
		if(!flag){
			errorMap.put(ConstantDefine.SYS_ERROR_KEY,  "保存操作失败，请重试！");
		}else{
			errorMap.put(ConstantDefine.SUCCESS, "数据已保存");
		}
		return errorMap;
	}
	
	/**
	 * 保存之前检测是否有相同记录，除了以下字段
	 * id,creator,createTime,modify,modifyTime
	 * @param entity
	 * @return
	 */
	public Map<String,Object> checkSameData(T entity){
		//检查数据是否存在
		return checkEntityExists(entity,"id","creator","createTime","modify","modifyTime");
	}
	
	
	public Map<String, Object> checkEntityExists(T entity,String... ignoreField){
		T entity2 = null;
		try {
			entity2 = (T) entity.getClass().newInstance();
		} catch (Exception e) {
			logger.error("查检存在相同记录时出现异常", e);
		}
		//复制对象属性时，去掉id、creator、createTime、modify、modifyTime，才能查询出是否有重复记录
		ReflectUtil.copyProperties(entity, entity2,true, ignoreField);
		List<T> old = select(entity2);
		Map<String,Object> errorMap = new HashMap<>();
		//数据存在
		if(old.size() > 0 ){
			errorMap.put(ConstantDefine.CHECK_ERR_MSG, "系统中已有该条数据");
			return errorMap;
		}
		return errorMap;
	}
	
    /**
	 * 根据主键更新实体
	 * @param entity 实体
	 * @param isUpdateNull ：true表示null值会被更新到数据库中，小心使用；
	 * 		
	 * @param ignoreField ：isUpdateNull为true时，可以忽略掉指定的字段不更新数据。
	 * 			id,creator,createTime不会被更新
	 * @return
	 */
	public Map<String, Object> checkAndUpdate(T entity,boolean isUpdateNull,String...ignoreField){
		//先调用数据校验
		Map<String,Object> errorMap = this.checkUpdate(entity);
		//存在错误则返回
		if(errorMap!=null && !errorMap.isEmpty()){
			return errorMap;
		}
		int result =0;
		//更新数据
		if(isUpdateNull){
			String id = ReflectUtil.getValueFromObject(entity,"id");
			T tar= selectByKey(id);
			String[] ig = new String[ignoreField.length + 3];
			ig[0]="id";
			ig[1]="creator";
			ig[2]="createTime";
			for(int i=3;i<ig.length;i++){
				ig[i]=ignoreField[i-3];
			}
			BeanUtils.copyProperties(entity, tar,ig);			
			result = updateByPrimaryKey(tar);
		} else {
			result = updateNotNull(entity);
		}
		errorMap = new HashMap<String,Object>();
		if(result > 0)
			errorMap.put(ConstantDefine.SUCCESS, ConstantDefine.SUCCESS_INFO);
		else 
			errorMap.put(ConstantDefine.CHECK_ERR_MSG, ConstantDefine.FAIL_INFO);
		return errorMap;		
	}
	
	
	
	/**
	 * 更新：先将旧数据失效，再插入新数据，方便追溯
	 * @param invalidEntity 失效实体
	 * @param newEntity  新实体
	 * @return
	 */
	public Map<String, Object> firstInvalidAndInsert(T invalidEntity,T newEntity){
		
		//校验更新数据
		Map<String,Object> errorMap = this.checkUpdate(newEntity);
		if(errorMap!=null && !errorMap.isEmpty()){
			return errorMap;
		}
		//将旧数据失效
		int result = this.updateByPrimaryKey(invalidEntity);
		errorMap = new HashMap<String,Object>();
		if(result <= 0){
			//操作失败，回滚数据
			throw new LogicException(ConstantDefine.FAIL_INFO);
		}
		boolean isSuccess = this.save(newEntity);
		if(!isSuccess){
			//操作失败，回滚数据
			throw new LogicException(ConstantDefine.FAIL_INFO);
		}
		errorMap.put(ConstantDefine.SUCCESS_MSG, ConstantDefine.SUCCESS_INFO);
		return errorMap;		
	}
	
	/**
	 * Created by wrl on 2017/07/10
	 * 单表或多表，需要实现mapper selectPaging sql
	 * @param entity
	 * @return
	 */
	@Override
	public PageInfo<T> selectDefaultPaging(T entity) {
		PageInfo<T> pageInfo= new PageInfo<>();
		pageInfo.setList(baseDAO.selectPaging(entity));
		return pageInfo;
	}

	/**
	 * Created by wrl on 2017/07/10
	 * 默认单表分页 sqlserver 需要 在dto 里添加 @Order
	 * @param entity
     * @return
     */
	@Override
	public PageInfo<T> selectCustomPaging(T entity) {
			
		return new PageInfo<>(baseDAO.selectWhereClausePaging(entity));
	}


	/**
	 * 实现自定义业务校验规则，保存、修改都会调用check方法进行校验
	 */
	public abstract Map<String, Object> check(T entity);
	
	/**
	 * 实现自定义业务校验规则，保存、修改都会调用check方法进行校验
	 */
	public abstract Map<String, Object> checkUpdate(T entity);


	/**
	 * 根据对象创建一个空的对象
	 * @param entity
	 * @return
	 */
	private T createInstance(T entity) throws IllegalAccessException, InstantiationException {
		Class clazz = entity.getClass();
		return (T)clazz.newInstance();
	}

	/**
	 * 验证字段的唯一性
	 * @param entity 实体
	 * @param fieldNames 需要验证的字段名
	 * @param explans 字段名对应的中文--用做错误信息返回。
	 * @param isUpdate true: 更新的验证，false:新增验证
	 * @return
	 */
	public Map uniqueCheck(T entity,String[] fieldNames, String[] explans,boolean isUpdate) {
//		AdvInfoDTO advInfoDTO = new AdvInfoDTO();
		//通过class 反射出一个空白的对象
		Map resultMap = new HashMap();
		try {
			Map fieldErrMap = new HashMap();
			if(fieldNames.length != explans.length){
				throw new RuntimeException("参数fieldNames长度与explans长度不一致");
			}
			for (int i = 0; i < fieldNames.length; i++){
				T t = createInstance(entity);
	//			依次验证各个字段是否重复--更新 和修改验证方式不同
				//更新时，验证的值没有更改的情况
				Method[] methods = entity.getClass().getMethods();
				String setMethodName = "set" + fieldNames[i].substring(0,1).toUpperCase() + fieldNames[i].substring(1);
				String getMethodName = "get" + fieldNames[i].substring(0,1).toUpperCase() + fieldNames[i].substring(1);
				Method getFieldMethod = getMethod(methods,getMethodName);
				Method setFieldMethod = getMethod(methods,setMethodName);
				getMethod(methods,"setNullStatus").invoke(t);

				//字段赋值
				setFieldMethod.invoke(t,getFieldMethod.invoke(entity));
				if(isUpdate){
					Method setIdMethod = getMethod(methods,"setId");
					Method getIdMethod = getMethod(methods,"getId");
	//				id赋值
					Object id = getIdMethod.invoke(entity);
					if(id == null){
						throw new RuntimeException("更新时ID不能为空");
					}
					setIdMethod.invoke(t,id);
					List<T> list = select(t);
					//能查到，则说明没有对需要判断的字段进行修改,则不重复
					if(list != null && list.size() > 0){
						continue;
					}else{
						//对该字段进行了修改--需要验证是否存在
						t = createInstance(entity);
						setFieldMethod.invoke(t,getFieldMethod.invoke(entity));
						getMethod(methods,"setNullStatus").invoke(t);
					}
				}
				//修改时对要检验字段做了修改，或者新增时
				List<T> list = select(t);
				if(list != null && list.size() > 0){
					//重复
					fieldErrMap.put(fieldNames[i],explans[i] + "已存在");
				}
			}
			if(!fieldErrMap.isEmpty()){
				resultMap.put(ConstantDefine.FIELD_ERR_MSG,fieldErrMap);
			}
		} catch (IllegalAccessException e) {
			logger.error(e.getMessage());
			resultMap.put(ConstantDefine.SYS_ERROR_KEY,ConstantDefine.SYS_ERR_MSG );
		} catch (InstantiationException e) {
			logger.error(e.getMessage());
			resultMap.put(ConstantDefine.SYS_ERROR_KEY,ConstantDefine.SYS_ERR_MSG );
		} catch (InvocationTargetException e) {
			logger.error(e.getMessage());
			resultMap.put(ConstantDefine.SYS_ERROR_KEY,ConstantDefine.SYS_ERR_MSG );
		}
		return resultMap;
	}

	/**
	 * 根据方法名从方法数组中找出方法
	 * @param methods
	 * @param methodName
	 * @return
	 */
	private Method getMethod(Method[] methods, String methodName){
		for (int i = 0; i < methods.length; i++){
			if(methods[i].getName().equals(methodName)){
				return methods[i];
			}
		}
		return null;
	}

	/**
	 * 通过返回的操作记录条数判断是否操作成功
	 * @param n
	 * @return
	 */
	public Map getResultMap(int n){
		Map resultMap = new HashMap();
		if(n>0){
			resultMap.put(ConstantDefine.SUCCESS,"操作成功");
		}else {
			resultMap.put(ConstantDefine.SYS_ERROR_KEY,"操作失败，请稍后重试");
		}
		return resultMap;
	}
}
